package com.atguigu.gmall.activity.receiver;

/**
 * @author sunjipu
 * @create 2020-04-25 9:20
 */

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 接收消息
 */
@Component
public class SeckillReceiver {


    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

//    //接收MQ消息
//    @RabbitListener(bindings = @QueueBinding(
//            value = @Queue(value = MqConst.QUEUE_TASK_1),
//            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
//            key = MqConst.ROUTING_TASK_1
//    ))
//    public void importDataToRedis(Message message, Channel channel) throws Exception {
//
//        //导入秒杀商品数据到Redis中
//        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
//        //审核状态 0：未审核  1：审核通过
//        queryWrapper.eq("status","1");
//        //库存大于0
//        queryWrapper.gt("stock_count",0);
//
//        //开始时间//结束时间  现在是凌晨一点  只要在今天
//        queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
//
//        //1:查询秒杀商品数据
//        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);
//
//        if(!CollectionUtils.isEmpty(seckillGoodsList)){
//            seckillGoodsList.forEach(seckillGoods -> {
//                //保存缓存中
//                Long skuId = seckillGoods.getSkuId();
//                redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS, skuId,seckillGoods);
//                //根据每一款商品的数量  准备集合
//                Long[] skuIds = new Long[seckillGoods.getStockCount()];
//                for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
//                    skuIds[i] = skuId;
//                }
//                redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX + skuId,skuIds);
//            });
//        }
//        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
//    }


    //接收MQ消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1
    ))
    public void importDataToRedis(Message message, Channel channel) throws Exception {

        //导入秒杀商品数据到Redis中
        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        //审核状态 0：未审核  1：审核通过
        queryWrapper.eq("status","1");
        //库存大于0
        queryWrapper.gt("stock_count",0);

        //开始时间//结束时间  现在是凌晨一点  只要在今天
        queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));

        //1:查询秒杀商品数据
        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);

        if(!CollectionUtils.isEmpty(seckillGoodsList)){
            seckillGoodsList.forEach(seckillGoods -> {

                Long skuId = seckillGoods.getSkuId();
                //判断缓存中是否有
                if(!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS, skuId.toString())){
                    //1:保存缓存中
                    redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS, skuId.toString(),seckillGoods);
                    //2:根据每一款商品的数量  准备集合
                    Long[] skuIds = new Long[seckillGoods.getStockCount()];
                    for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
                        skuIds[i] = skuId;
                    }
                    redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX + skuId,skuIds);
                    //3:Redis发布、订阅模式
                    redisTemplate.convertAndSend("seckillpush",skuId+":1");
                }
            });
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 秒杀用户加入队列
     *
     * @param message
     * @param channel
     * @throws IOException
     */
//接收消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER
    ))


    public void seckill(Message message, Channel channel, UserRecode userRecode) throws Exception {
        Long skuId = userRecode.getSkuId();
        String userId = userRecode.getUserId();
        String state = (String) CacheHelper.get(skuId.toString());
        //1://产品状态位， 1：可以秒杀 0：秒杀结束
        if("0".equals(state)){
            //已售罄
            return;
        }
        //2: //判断用户是否下单
        Boolean isExist = redisTemplate.opsForValue().setIfAbsent(RedisConst.SECKILL_USER +
                        userId, skuId,
                RedisConst.SECKILL__TIMEOUT, TimeUnit.SECONDS);
        if(!isExist){
            return;//此用户已经买过了、不能再买了
        }
        //3: //获取队列中的商品，如果能够获取，则商品存在，可以下单
        String id = (String) redisTemplate.opsForList().
                rightPop(RedisConst.SECKILL_STOCK_PREFIX + skuId);
        if(StringUtils.isEmpty(id)){
            //商品售罄，更新状态位
            redisTemplate.convertAndSend("seckillpush", skuId + ":0");
            return;
        }
        //4：可以下单了
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userId);
        orderRecode.setNum(1);
        SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.opsForHash()
                .get(RedisConst.SECKILL_GOODS, skuId.toString());
        orderRecode.setSeckillGoods(seckillGoods);
        orderRecode.setOrderStr(MD5.encrypt(userId + skuId));
        //保存预订单
        redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDERS + userId,orderRecode);

        //更新商品的库存
        this.updateStockCount(skuId);
        //应答
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    private void updateStockCount(Long skuId) {
        Long size = redisTemplate.opsForList().size(RedisConst.SECKILL_STOCK_PREFIX + skuId);
        if(size%2 == 0){
            SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.opsForHash()
                    .get(RedisConst.SECKILL_GOODS,skuId);
            seckillGoods.setStockCount(size.intValue());
            //更新缓存中的库存
            redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,skuId,seckillGoods);
            //更新Mysql数据库的库存
            seckillGoodsMapper.updateById(seckillGoods);
        }

    }


/**
 * 秒杀结束清空缓存
 *
 * @param message
 * @param channel
 * @throws IOException
 */

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, durable = "true", type = ExchangeTypes.DIRECT),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearRedis(Message message, Channel channel) throws IOException {

        //活动结束清空缓存
        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        queryWrapper.le("end_time", new Date());
        List<SeckillGoods> list = seckillGoodsMapper.selectList(queryWrapper);
        //清空缓存
        for (SeckillGoods seckillGoods : list) {
            redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId());
        }
        redisTemplate.delete(RedisConst.SECKILL_GOODS);
        redisTemplate.delete(RedisConst.SECKILL_ORDERS);
        redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
        //将状态更新为结束
        SeckillGoods seckillGoodsUp = new SeckillGoods();
        seckillGoodsUp.setStatus("2");
        seckillGoodsMapper.update(seckillGoodsUp, queryWrapper);
        // 手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

}
